package com.panopset.games;

import java.io.File;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Vector;

import com.panopset.Strings;
import com.panopset.UtilIO;

/**
 * Generic high score list which keeps track of the names and scores of ten
 * players, in a file. File format: line 1 is a name, line 2 is the score, etc.
 * for 20 total lines.
 *
 * @author Karl Dinwiddie
 *
 */
public final class HighScores {

    /**
     * Keep track of up to 10 scores. Applications may change this in
     * initialization.
     */
    public static int MAX_SCORES = 10;

    /**
     * Scores file.
     */
    private final File f;

    /**
     * High scores.
     *
     * @param File
     *            to store high score list in 20 lines.
     */
    public HighScores(final String file) {
        f = new File(file);
    }

    public List<Score> getScores() {
        List<Score> rtn = new ArrayList<Score>();
        if (!f.exists()) {
            UtilIO.createNewFile(f);
        }
        Vector<String> lines = UtilIO.loadFile(f);
        for (int l = 0; (l / 2) < MAX_SCORES; l = l + 2) {
            String name = "";
            Long value = 0L;
            if (l + 1 < lines.size()) {
                name = lines.elementAt(l);
                String sv = lines.elementAt(l + 1);
                try {
                    value = Long.parseLong(sv);
                } catch (NumberFormatException ex) {
                    value = 0L;
                }
            }
            rtn.add(new Score(name, value));
        }
        return rtn;
    }

    /**
     * @param name Name.
     * @param value Value.
     * @return true if this was one of the high scores, false if not.
     * Useful for a "Congratulations" message.
     */
    public boolean setScore(final String name, final Long value) {
        if (name == null) {
            return false;
        }
        List<Score> scores = getScores();
        if (scores.size() == MAX_SCORES) {
            if (((Score) (scores.toArray()[MAX_SCORES - 1])).getValue() >= value) {
                return false;
            }
        }
        scores.add(new Score(name, value));
        save(scores);
        return true;
    }

    private void save(List<Score> scores) {
        Collections.sort(scores);
        StringWriter sw = new StringWriter();
        int i = 0;
        FOR: for (Score score : scores) {
            if (i < MAX_SCORES) {
                sw.append(score.getName());
                sw.append(Strings.getEol());
                sw.append("" + score.getValue());
                sw.append(Strings.getEol());
            } else {
                break FOR;
            }
            i++;
        }
        UtilIO.saveStringToFile(sw.toString(), f);
    }

    public static final class Score implements Comparable<Score> {

        /**
         * @param name
         * @param value
         */
        public Score(final String name, final Long value) {
            setName(name);
            setValue(value);
        }

        /**
         * Create empty score.
         */
        public Score() {
            this("", 0L);
        }

        /**
         * Name.
         */
        private String n;

        /**
         * Score.
         */
        private Long v;

        /**
         * @return Name.
         */
        public String getName() {
            if (n == null) {
                n = "";
            }
            return n;
        }

        /**
         * @param name
         *            Name.
         */
        public void setName(final String name) {
            n = name;
        }

        /**
         * @return Score.
         */
        public Long getValue() {
            if (v == null) {
                v = 0L;
            }
            return v;
        }

        /**
         * @param score
         *            Score.
         */
        public void setValue(final Long value) {
            v = value;
        }

        @Override
        public int compareTo(Score o) {
            // Obtain a descending sequence by reversing the compare.
            return o.getValue().compareTo(this.getValue());
        }
    }

    public void clear() {
        UtilIO.saveStringToFile("", f);
    }
}
